﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Diagnostics;

namespace ShevaEngine.Core.Modules.Models
{
    /// <summary>
    /// Contains information about an animation.
    /// </summary>
    [ContentSerializerRuntimeTypeAttribute("ShevaEngine.Core.Modules.Models.AnimationInfo, ShevaEngine2")]
    public class AnimationInfo
    {
        /// <summary>Gets the name of the animation.</summary>
        public string Name { get; set; }
        /// <summary>Gets the total duration of this animation in ticks.</summary>
        public long Duration { get; set; }
        /// <summary>Gets a collection of channels that represent the bone animation
        /// tracks for this animation.</summary>
        public AnimationChannelCollection AnimationChannels { get; set; }

        /// <summary>Gets a collection of bones that have tracks in this animation.</summary>
        [ContentSerializerIgnore]
        public List<string> AffectedBones
        {
            get { return this.AnimationChannels.AffectedBones; }
        }

        /// <summary>
        /// Konstruktor.
        /// </summary>
        public AnimationInfo()
        {

        }

        /// <summary>
        /// Internal because it should only be created by the AnimationReader.
        /// </summary>
        /// <param name="animationName"></param>
        /// <param name="anims"></param>
        public AnimationInfo(string animationName, long duration, AnimationChannelCollection anims)
        {
            this.Name = animationName;
            this.Duration = duration;
            this.AnimationChannels = anims;

            foreach (BoneKeyframeCollection channel in anims.Values)
                if (this.Duration < channel.Duration)
                    this.Duration = channel.Duration;
        }

        /// <summary>
        /// Returns true if the animation contains any tracks that affect the given
        /// bone.
        /// </summary>
        /// <param name="boneName">The bone to test for track information.</param>
        /// <returns>True if the animation contains any tracks that affect the given
        /// bone.</returns>
        public bool AffectsBone(string boneName)
        {
            return this.AnimationChannels.AffectsBone(boneName);
        }
    }

    /// <summary>
    /// A collection of AnimationInfo objects.
    /// </summary>
    [ContentSerializerRuntimeTypeAttribute("ShevaEngine.Core.Modules.Models.AnimationInfoCollection, ShevaEngine2")]
    public class AnimationInfoCollection : List<AnimationInfo>
    {
        // New instances should only be created by the AnimationReader
        public AnimationInfoCollection()
        {
        }

        /// <summary>
        /// Gets a collection of animations stored in the model.
        /// </summary>
        /// <param name="model">The model that contains the animations.</param>
        /// <returns>The animations stored in the model.</returns>
        public static AnimationInfoCollection FromModel(Model model)
        {
            // Grab the tag that was set in the processor; this is a dictionary so that users can extend
            // the processor and pass their own data into the program without messing up the animation data
            Dictionary<string, object> modelTagData = (Dictionary<string, object>)model.Tag;
            if (modelTagData == null || !modelTagData.ContainsKey("Animations"))
            {
                return new AnimationInfoCollection();
            }
            else
            {
                AnimationInfoCollection animations = (AnimationInfoCollection)modelTagData["Animations"];
                return animations;
            }
        }

        ///// <summary>
        ///// Gets the AnimationInfo object at the given index.
        ///// </summary>
        ///// <param name="index">The index of the AnimationInfo object.</param>
        ///// <returns>The AnimationInfo object at the given index.</returns>
        //public AnimationInfo this[int index]
        //{
        //    get
        //    {
        //        return this[index];
        //    }
        //}
    }

    /// <summary>
    /// A collection of animation channels or tracks, which are sections of an
    /// animation that run for one bone.
    /// </summary>
    [ContentSerializerRuntimeTypeAttribute("ShevaEngine.Core.Modules.Models.AnimationChannelCollection, ShevaEngine2")]
    public class AnimationChannelCollection : Dictionary<string, BoneKeyframeCollection>
    {
        /// <summary>Affected bones.</summary>
        public List<string> AffectedBones
        {
            get { return new List<string>(this.Keys); }
        }

        /// <summary>
        /// Konstruktor pro content pipeline.
        /// </summary>
        public AnimationChannelCollection()
            : base()
        { }

        // This immutable data structure should not be created by the library user
        public AnimationChannelCollection(Dictionary<string, BoneKeyframeCollection> channels)
            : base(channels)
        {
            ////            Debugger.Launch();

            //            // Find the affected bones
            //            //this.affectedBones = new List<string>();
            //            this.BoneKeyframes = new Dictionary<string, BoneKeyframeCollection>();

            //            foreach (BoneKeyframeCollection frames in channels)
            //            {
            //                BoneKeyframes.Add(frames.BoneName, frames);
            //              //  affectedBones.Add(frames.BoneName);
            //            }                       
        }

        ///// <summary>
        ///// Gets the BoneKeyframeCollection that is associated with the given bone.
        ///// </summary>
        ///// <param name="boneName">The name of the bone that contains a track in this
        ///// AnimationChannelCollection.</param>
        ///// <returns>The track associated with the given bone.</returns>
        //[ContentSerializerIgnore]
        //public BoneKeyframeCollection this[string boneName]
        //{
        //    get { return this[boneName]; }
        //}

        // See AnimationInfo's equivalent method for documentation        
        public bool AffectsBone(string boneName)
        {
            return this.ContainsKey(boneName);
        }
    }
}
